package com.yesep.learn.hik.ws;

import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.sun.jna.NativeLong;
import com.yesep.learn.hik.handle.HikHandle;
import com.yesep.learn.hik.model.Command;
import com.yesep.learn.hik.model.Hik;
import com.yesep.learn.hik.model.R;
import com.yesep.learn.hik.sdk.SDKUtils;
import com.yesep.learn.hik.service.IHikService;
import com.yesep.learn.hik.utils.SpringUtil;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

/**
 * websocket 服务端
 */
@ServerEndpoint(value = "/ws/{sid}")
@Component
public class WebSocketServer {

	private static Log log = LogFactory.get(WebSocketServer.class);

	private IHikService hikService;

	//key:sessionId   value:HikHandle 缓存map
	public static Map<String, HikHandle> handleOnlineMap = new ConcurrentHashMap<>();

	/**
	 * 连接建立成功调用的方法
	 *
	 * @param session
	 * @param sid
	 */
	@OnOpen
	public void onOpen(Session session, @PathParam("sid") String sid) {
		log.info("有新窗口开始监听:[{}]", sid);
		try {
			hikService = SpringUtil.getObject(IHikService.class);
			Hik hik = hikService.findHikByIp(sid);
			log.debug("hik.getLChannel() = " + hik.getLChannel());
			//设置处理类信息
			HikHandle hikHandle = new HikHandle(hik); //初始化SDK
			if (hikHandle.login().intValue() == -1) {
				sendMessage("登录失败", session);
				return;
			}
			hikHandle.setSid(sid);
			hikHandle.setSession(session);
			hikHandle.setLRealHandle(new NativeLong(0));
			hikHandle.setLastTime(new Date());

			handleOnlineMap.put(session.getId(), hikHandle);

			log.info("hikHandle.getUserId() = [{}]", hikHandle.getUserId());

			sendMessage("连接成功", session);
		} catch (Exception e) {
			log.error("websocket异常" + e.getMessage());
		}
	}

	/**
	 * 连接关闭调用的方法
	 *
	 * @param session
	 */
	@OnClose
	public void onClose(Session session) {
		handleOnlineMap.remove(session.getId());
		HikHandle hikHandle = handleOnlineMap.get(session.getId());
		//关闭连接 注销对应设备
		boolean logout = SDKUtils.getHCNetSDK().NET_DVR_Logout(hikHandle.getUserId());
		try {
			sendMessage("断开连接" + (logout ? "成功" : "失败"), session);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 收到客户端消息后调用的方法
	 *
	 * @param message 客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		HikHandle hikHandle = handleOnlineMap.get(session.getId());
		log.info("收到来自窗口 [{}] 的信息: [{}]", hikHandle.getSid(), message);
		Command command = JSONObject.parseObject(message, Command.class);
		hikHandle.execute(command); //执行命令
		try {
			sendMessage(command.toJson(), session);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 发生错误调用的方法
	 *
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		error.printStackTrace();
		HikHandle hikHandle = handleOnlineMap.get(session.getId());
		if (null == hikHandle)
			return;
		log.error("系统异常" + hikHandle.getSid());
		try {
			sendMessage("系统错误" + error.getMessage(), session);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 实现服务器主动推送
	 *
	 * @param message
	 * @throws IOException
	 */
	public void sendMessage(String message, Session session) throws IOException {
		session.getBasicRemote().sendText(R.me(1, message).toJson());
	}

	/**
	 * 群发自定义消息
	 */
	public void sendMessage(String message) throws IOException {
		log.info("群发推送内容:[{}]", message);
		for (Map.Entry<String, HikHandle> handleEntry : handleOnlineMap.entrySet()) {
			HikHandle handle = handleEntry.getValue();
			sendMessage(message, handle.getSession());
		}
	}

}
